package file_reference_impl

import (
	"context"
	"fmt"
	"io"
	"mime/multipart"
	"net/http"
	"nexus/dto"
	"nexus/internal/svc"
	"nexus/internal/types"
	"nexus/model"
	"nexus/utils"
	"os"
	"path"

	"github.com/suyuan32/knife/core/io/filex"
	"github.com/zeromicro/go-zero/core/logc"
	"gorm.io/gorm"
)

type FileReferenceImpl struct {
	svc *svc.ServiceContext
}

func NewFileReferenceImpl(svc *svc.ServiceContext) FileReference {
	return &FileReferenceImpl{
		svc: svc,
	}
}

// 上传文件
func (impl *FileReferenceImpl) UploadFile(ctx context.Context, req *http.Request) (*dto.File, error) {
	// 获取文件
	file, fileHandler, err := req.FormFile("file")
	if err != nil {
		return nil, err
	}
	defer file.Close()

	// 校验文件扩展名
	ext, isAllowed := utils.IsFileExtensionAllowed(fileHandler.Filename)
	if !isAllowed {
		return nil, err
	}

	// 填充模型并保存到数据库
	fileModel := &model.File{
		OriginalName: fileHandler.Filename,
		DisplayName:  fileHandler.Filename,
		FileType:     ext,
		Path:         utils.FileStoragePath(ext),
		Status:       1,
	}

	// 保存文件到服务器
	filePath := path.Join(impl.svc.Config.Static.UploadDir, fileModel.Path)
	fmt.Println("文件保存路径: ", filePath)
	if err := impl.saveFileToLocal(ctx, filePath, file); err != nil {
		logc.Errorf(ctx, "保存文件错误: %v", err)
		return nil, err
	}

	// 保存文件信息到数据库
	err = model.NewFileClient((*gorm.DB)(impl.svc.NexusDB)).UploadFile(fileModel)
	if err != nil {
		logc.Errorf(ctx, "文件信息保存错误: %v", err)
		return nil, err
	}

	// 将model层返回的File转换为DTO层的File
	data := dto.NewDTOTransfer().FileToDTO(fileModel)

	return data, nil
}

// 保存文件到服务器
func (impl *FileReferenceImpl) saveFileToLocal(ctx context.Context, filePath string, file multipart.File) error {
	dir := path.Dir(filePath)
	if err := filex.MkdirIfNotExist(dir, filex.SuperPerm); err != nil {
		logc.Errorf(ctx, "创建文件目录错误: %v", err)
		return err
	}

	targetFile, err := os.Create(filePath)
	if err != nil {
		logc.Errorf(ctx, "创建文件[%s]错误: %v", filePath, err)
		return err
	}
	defer targetFile.Close()

	if _, err = io.Copy(targetFile, file); err != nil {
		logc.Errorf(ctx, "文件[%s]拷贝错误: %v", filePath, err)
		return err
	}

	return nil
}

// 文件流预览
func (impl *FileReferenceImpl) GetFile(ctx context.Context, req *types.FilePreviewReq) (*dto.File, error) {
	// 组装查询条件
	condition := &model.FileCondition{
		ID: req.FileID,
	}

	// 查询文件信息
	file, err := model.NewFileClient((*gorm.DB)(impl.svc.NexusDB)).FindFileByCondition(condition)
	if err != nil {
		logc.Errorf(ctx, "查询文件信息错误: %v", err)
		return nil, err
	}

	// 将model层返回的File转换为DTO层的File
	data := dto.NewDTOTransfer().FileToDTO(file)

	return data, nil
}
